package com.carful.xigua.modules.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carful.cache.service.SmsCacheServiceImpl;
import com.carful.v10.entity.HyInfo;
import com.carful.v10.service.V10Service;
import com.carful.xigua.modules.common.config.SecurityConfig;
import com.carful.xigua.modules.common.util.JwtUtils;
import com.carful.xigua.modules.common.util.SecurityContextUtils;
import com.carful.xigua.modules.common.util.SpringContextUtil;
import com.carful.xigua.modules.user.entity.*;
import com.carful.xigua.modules.user.entity.Record;
import com.carful.xigua.modules.user.mapper.UserMapper;
import com.carful.xigua.modules.user.service.IUserService;
import com.carful.xigua.modules.xigua.entity.System;
import com.carful.xigua.modules.xigua.service.impl.SystemServiceImpl;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author ad
 * @since 2024-04-07
 */
@Slf4j
@Transactional(rollbackFor = { Exception.class })
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Value("${spring.application.name}")
    private String name;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private SecurityContextLogoutHandler securityContextLogoutHandler;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private SmsCacheServiceImpl smsCacheService;

    @Autowired
    private V10Service v10Service;

    @Autowired
    private RecordServiceImpl recordService;

    @Autowired
    private RoleServiceImpl roleService;

    @Autowired
    private UserRoleServiceImpl userRoleService;

    @Autowired
    private SystemServiceImpl systemService;

    @Override
    public void init() {
        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, name));
        if (user == null) {
            user = new User();
            user.setUsername(name).setPassword(passwordEncoder.encode("carful-" + name));
            save(user);
        }

        Role role = roleService.getOne(new LambdaQueryWrapper<Role>().eq(Role::getValue, "admin"));
        UserRole userRole = new UserRole().setUserId(user.getId()).setRoleId(role.getId());
        if (userRoleService.getOne(new LambdaQueryWrapper<>(userRole)) == null) {
            boolean insert = userRoleService.save(userRole);
            if (!insert) {
                log.error("管理员账号绑定角色失败");
            }
        }
    }

    @Override
    public User selectOne(String username) {
        return getBaseMapper().selectOne(username);
    }

    @Override
    public User daoLogin(User user) {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
        AuthenticationManager authenticationManager = SpringContextUtil.getBean(AuthenticationManager.class);

        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        SecurityConfig.LoginUserDetails principal = (SecurityConfig.LoginUserDetails) authenticate.getPrincipal();
        SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(principal.getUser(), null, principal.getAuthorities()));

        return principal.getUser();
    }

    @Override
    public User phoneLogin(String phone) {
        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getUserPhone, phone));
        if (user == null) {
            user = new User();
            user.setUserPhone(phone);
            user.setUsername(phone);

            // 更新会员信息
            info(user);

            System sys = systemService.getInfo();
            if (sys.getCurrentNumber() == 0) {
                throw new RuntimeException("西瓜被领取完了，等待补充");
            }
            sys.setCurrentNumber(sys.getCurrentNumber() - user.getCnt());
            systemService.updateById(sys);
            save(user);
        } else if (!StringUtils.hasText(user.getMemberName())) {
            info(user);
            updateById(user);
        }

        return user;
    }

    /**
     * 设置会员信息
     * @param user
     */
    public void info(User user) {
        List<HyInfo> memberInfo = v10Service.getMemberInfo(user.getUserPhone(), null);
        if (memberInfo == null || memberInfo.size() == 0) throw new RuntimeException("不是会员");
        sortHyInfo(memberInfo);
        int maxCount = getMaxCount(memberInfo);
        user.setRealName(memberInfo.get(0).getHYMC());
        user.setMemberName(memberInfo.get(0).getHYKZLMC());
        user.setHYJF(memberInfo.get(0).getHYJF());
        user.setCnt(maxCount);
        user.setCurrentCnt(maxCount);

    }

    public void info(User user, List<HyInfo> memberInfo) {
        sortHyInfo(memberInfo);
        user.setRealName(memberInfo.get(0).getHYMC());
        user.setMemberName(memberInfo.get(0).getHYKZLMC());
        user.setHYJF(memberInfo.get(0).getHYJF());
    }


    @Override
    public boolean daoLogout(HttpServletRequest request, HttpServletResponse response) {
        //  获取 token
        String token = Objects.requireNonNull(jwtUtils.getTokenFromRequest(request), "未登录");
        Authentication authentication = SecurityContextUtils.getAuthentication();
        jwtUtils.validateToken(token, (UserDetails) authentication.getPrincipal());
        // 将token设置为无效
        jwtUtils.invalidateToken(token);
        securityContextLogoutHandler.logout(request, response, authentication);
        return true;
    }

    @Override
    public boolean updPassword(String oldPassword, String newPassword) {
        User user = SecurityContextUtils.getLoginUserDetails().getUser();
        if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
            throw new RuntimeException("密码错误");
        }
        int i = getBaseMapper().updateById(user.setPassword(passwordEncoder.encode(newPassword)));
        return i != 0;
    }

    @Override
    @Transactional(rollbackFor = { Exception.class })
    public String bindPhone(User user, String token, String phone, String phoneCode) {
        if (!smsCacheService.get(phone).equals(phoneCode)) {
            throw new RuntimeException("验证码错误或已失效");
        }

        User jflUser = new User();
        jflUser.setId(user.getId());
        jflUser.setUserPhone(phone);
        updateById(jflUser);

        // 删除缓存
        smsCacheService.expire(phone);
        return null;
    }

    @Override
    public User getUserByOpenid(String openid) {
        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getOpenid, openid));
        if (null == user) {
            user = new User();
            user.setOpenid(openid);
            user.setUsername(openid);
            save(user);
            log.info("创建账号： {}", openid);
        }
        return user;
    }

    @Override
    @Transactional(rollbackFor = { Exception.class })
    public String getXiguaCode(String username) {

        User user1 = getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username).last("for update"));

        if (user1.getCurrentCnt() <= 0) {
            throw new RuntimeException("次数不足");
        }
        String code = username + "-" + java.lang.System.currentTimeMillis();
        return code;
    }


    @Override
    @Transactional(rollbackFor = { Exception.class })
    public String getXigua(String username, User user) {

        User user1 = getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username).last("for update"));
        if (null == user1) throw new RuntimeException("用户不存在");
        if (!StringUtils.hasText(user1.getUserPhone()) && !StringUtils.hasText(user1.getMember())) {
            throw new RuntimeException("请绑定手机号或会员码");
        }

        if (user1.getCurrentCnt() <= 0) {
            throw new RuntimeException("次数不足");
        }
        // 保存领取信息
        Record record = new Record();
        record.setPhone(user1.getUserPhone());
        record.setMember(user1.getRealName());
        record.setUserId(user.getId());
        record.setOrgName(user.getOrgName());
        recordService.save(record);

        User user2 = new User();
        user2.setId(user1.getId());
        user2.setCurrentCnt(user1.getCurrentCnt() - 1);
        updateById(user2);
        return "领取成功";
    }

    @Override
    public List<HyInfo> sortHyInfo(List<HyInfo> memberInfo) {
        memberInfo.sort((a, b) -> {
            int counta = 0, countb = 0;
            double jfa = 0, jfb = 0;
            try {
                counta = Member.valueOf(a.getHYKZLMC()).getCount();
                jfa = a.getHYJF();
            } catch (Exception e) {
            }
            try {
                counta = Member.valueOf(b.getHYKZLMC()).getCount();
                jfa = b.getHYJF();
            } catch (Exception e) {
            }
            int compare = Integer.compare(counta, countb);
            if (compare != 0) return compare;
            return Double.compare(jfa, jfb);
        });
        return memberInfo;
    }

    /**
     * V10 会员信息获取 领取西瓜最大次数
     * @param hyInfoList
     * @return
     */
    public int getMaxCount(List<HyInfo> hyInfoList) {
        // 转换枚举类获取次数
        ArrayList<Member> members = new ArrayList<>();
        for (HyInfo hyInfo : hyInfoList) {
            try {
                Member member = Member.valueOf(hyInfo.getHYKZLMC());
                members.add(member);
            } catch (Exception e) {
                log.error("会员卡类型 【{}】 不在程序", hyInfo.getHYKZLMC());
            }
        }
        // 取最大值
        int count = members.stream().max(Comparator.comparingInt(Member::getCount)).get().getCount();

        return count;
    }

    /**
     * 已领取次数
     * @param user
     * @return
     */
    public int getUseCount(User user) {
        // 查询已经领取次数
        LambdaQueryWrapper<Record> wrapper = new LambdaQueryWrapper<Record>()
                .eq(user.getUserPhone() != null, Record::getPhone, user.getUserPhone()).last("for update");
        long count1 = recordService.count(wrapper);
        return (int)count1;
    }
}
